package com.gym.redis;

import com.alibaba.fastjson.JSON;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * redis服务
 *
 * @author gym
 */
@Service
public class RedisService {

    @Resource
    JedisPool jedisPool;

    /**
     * 从redis连接池获取redis实例
     */
    public <T> T get(KeyPrefix prefix, String key, Class<T> clazz) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            // 对key增加前缀，即可用于分类，也避免key重复
            String realKey = prefix.getPrefix() + key;
            String str = jedis.get(realKey);
            T t = stringToBean(str, clazz);
            return t;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 根据key获取value值
     */
    public JSONObject getValue(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String string = jedis.get(key);
            JSONObject object = JSONObject.fromObject(string);
            return object;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 存储对象
     */
    public <T> Boolean set(KeyPrefix prefix, String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String str = beanToString(value);
            if (str == null || str.length() <= 0) {
                return false;
            }
            String realKey = prefix.getPrefix() + key;
            // 获取过期时间
            int seconds = prefix.expireSeconds();
            if (seconds <= 0) {
                jedis.set(realKey, str);
            } else {
                jedis.setex(realKey, seconds, str);
            }
            return true;
        } finally {
            returnToPool(jedis);
        }

    }

    /**
     * 删除
     */
    public boolean delete(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            // 生成真正的key
            String realKey = prefix.getPrefix() + key;
            long ret = jedis.del(realKey);
            return ret > 0;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public boolean deleteKey(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            long ret = jedis.del(key);
            return ret > 0;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 判断key是否存在
     */
    public <T> boolean exists(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            // 生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.exists(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 查询所有的key
     */
    public Jedis getAllKey() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis;
        } finally {
            returnToPool(jedis);
        }

    }

    /**
     * 增加值 Redis Incr 命令将 key 中储存的数字值增一。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCR
     * 操作
     */
    public <T> Long incr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            // 生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.incr(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 减少值
     */
    public <T> Long decr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            // 生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.decr(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    public static <T> String beanToString(T value) {
        if (value == null) {
            return null;
        }
        Class<?> clazz = value.getClass();
        if (clazz == int.class || clazz == Integer.class) {
            return String.valueOf(value);
        } else if (clazz == long.class || clazz == Long.class) {
            return String.valueOf(value);
        } else if (clazz == String.class) {
            return (String) value;
        } else {
            return JSON.toJSONString(value);
        }

    }

    @SuppressWarnings("unchecked")
    public static <T> T stringToBean(String str, Class<T> clazz) {
        if (str == null || str.length() <= 0 || clazz == null) {
            return null;
        }
        if (clazz == int.class || clazz == Integer.class) {
            return (T) Integer.valueOf(str);
        } else if (clazz == long.class || clazz == Long.class) {
            return (T) Long.valueOf(str);
        } else if (clazz == String.class) {
            return (T) str;
        } else {
            return JSON.toJavaObject(JSON.parseObject(str), clazz);
        }
    }

    /**
     * 返回删除redis
     *
     * @param <T>         实体对象
     * @param prefixKey   redisKey的前缀
     * @param clazz       实体对象
     * @param uniqueRedis redis唯一标识值
     * @param uniqueDb    数据库唯一标识值
     * @return
     */
    public <T> Boolean deleteKeys(String prefixKey, T clazz, String uniqueRedis, String uniqueDb) {
        try {
            // 查询缓存中关于的key值
            Set<String> keys = getAllKey().keys(prefixKey + "*");
            Object object = null;
            // 遍历所有的key值
            for (String key : keys) {
                // 获得key值对应的value值
                JSONObject value = getValue(key);
                object = value.get("list");
                Iterator<T> it = ((List<T>) object).iterator();
                // 遍历value中的数组
                while (it.hasNext()) {
                    // 遍历后的结果转换为json
                    JSONObject object2 = JSONObject.fromObject(it.next());
                    Object object3 = object2.get(uniqueRedis);
                    // 比较缓存中的值和数据库中的值，如果有相同，如果相同，那么删除缓存中的key值
                    if (object3.toString().equals(uniqueDb)) {
                        deleteKey(key);
                    } else {
                        return false;
                    }
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除关联数据的key值
     *
     * @param <T>
     * @param prefixKey     redisKey的前缀
     * @param clazz         实体对象
     * @param uniqueRedis01 redis唯一标识值
     * @param uniqueRedis02 list中集合的对象key
     * @param uniqueDb      数据可以的唯一值
     * @return
     */
    public <T> Boolean deleteKeysAssociated(String prefixKey, T clazz, String uniqueRedis01, String uniqueRedis02,
                                            String uniqueDb) {
        try {
            // 查询缓存中关于的key值
            Set<String> keys = getAllKey().keys(prefixKey + "*");
            Object object = null;
            // 遍历所有的key值
            for (String key : keys) {
                // 获得key值对应的value值
                JSONObject value = getValue(key);
                object = value.get("list");
                Iterator<T> it = ((List<T>) object).iterator();
                // 遍历value中的数组
                while (it.hasNext()) {
                    // 遍历后的结果转换为json
                    JSONObject object2 = JSONObject.fromObject(it.next());
                    // 获取关联的对象
                    Object object3 = object2.get(uniqueRedis01);
                    JSONObject fromObject = JSONObject.fromObject(object3);
                    for (int i = 0; i < fromObject.size(); i++) {
                        // 获取关联里面的唯一值
                        Object object4 = fromObject.get(uniqueRedis02);
                        // 比较缓存中的值和数据库中的值，如果有相同，如果相同，那么删除缓存中的key值
                        if (object4.toString().equals(uniqueDb)) {
                            deleteKey(key);
                        } else {
                            return false;
                        }

                    }

                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除所有的rediskey
     *
     * @param pageById redis键ID
     * @param pageList redis键列表
     * @return
     */
    public boolean redisAllKey(String pageById, String pageList) {

        try {
            // 处理缓存
            Set<String> keys = getAllKey().keys(pageList + "*");
            for (String key : keys) {
                deleteKey(key);
            }
            Set<String> keys2 = getAllKey().keys(pageById + "*");
            for (String key : keys2) {
                deleteKey(key);
            }
            return true;
        } catch (Exception e) {
            return false;
        }

    }

    private void returnToPool(Jedis jedis) {
        if (jedis != null) {
            jedis.close();// 不是关闭，只是返回连接池
        }
    }

}
